/**
 * @class   wosh::Permission
 * @brief   Hold permission and user information of an Object
 *
 ****************************************************************************
 * @version 0.8.384 $Id: Permission.h 2863 2010-08-07 04:28:58Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR PermissionS;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

#ifndef __WOSH_Core_Permission_H__
 #define __WOSH_Core_Permission_H__

 #include <woshDefs.h>
 #include <core/Serialization.h>


namespace wosh {

class PermissionManager;

class Permission : public ISerializable
 {
	WOSH_SERIALIZABLE(wosh::Permission)
	WOSH_COMPARE_RTTI(wosh::Permission)

	public:
		/// rights
		enum PERMISSION_TYPE { // 4 bits
			None		= 0x00,	///< [0000]
			Execute		= 0x01,	///< [0001]
			Write		= 0x02,	///< [0010]
			WX			= 0x03,	///< [0011]
			Read		= 0x04,	///< [0100]
			RX			= 0x05,	///< [0101]
			RW			= 0x06,	///< [0110]
			RWX			= 0x07	///< [0111]
		};

		static inline bool isValidMask( PERMISSION_TYPE v ) { return v >= Permission::None  && v < Permission::RWX; }

		/// mask used when overwriting/updating permissions (usually by parent/on initialization)
		enum PERMISSION_OVERWRITE { // 1 byte
			Overwrite_None			= 0x00,	///< [0000 0000] (0)
			Overwrite_Owner			= 0x01,	///< [0000 0001] (1)
			Overwrite_Group			= 0x02,	///< [0000 0010] (2)
			Overwrite_MaskOwner		= 0x04,	///< [0000 0100] (4)
			Overwrite_MaskGroup		= 0x08,	///< [0000 1000] (8)
			Overwrite_MaskOthers	= 0x10,	///< [0001 0000] (16)
			// provided for convenience:
			Overwrite_OwnerGroup	= 0x03,	///< [0000 0011] (3)
			Overwrite_MaskAll		= 0x1C,	///< [0001 1100] (28)
			Overwrite_All			= 0xFF,	///< [1111 1111] (255)
		};

		static inline bool isValidOverwrite( short v ) { return v >= Permission::Overwrite_None  && v < Permission::Overwrite_All; }

	public:
		/**
		 * @brief  Empty constructor.
		 */
		Permission();
		/**
		 * @brief  Constructor with initializer(s), provided for convenience.
		 * @param [in] mask the rights-mask string to be assigned (example: 'rwxr-wxr--')
		 */
		Permission( const std::string& mask );
		/**
		 * @brief  Constructor with initializer(s), provided for convenience.
		 * @param [in] owner_mask the rights-mask to be assigned for the owner
		 * @param [in] group_mask the rights-mask to be assigned for the group
		 * @param [in] others_mask the rights-mask to be assigned for others
		 */
		Permission( Permission::PERMISSION_TYPE owner_mask, Permission::PERMISSION_TYPE group_mask, Permission::PERMISSION_TYPE others_mask );
		/**
		 * @brief  Constructor with initializer(s), provided for convenience.
		 * @param [in] ownername the username of the owner to be assigned
		 * @param [in] groupname the name of the group to be assigned
		 * @param [in] owner_mask the rights-mask to be assigned for the owner
		 * @param [in] group_mask the rights-mask to be assigned for the group
		 * @param [in] others_mask the rights-mask to be assigned for others
		 */
		Permission( const std::string& ownername, const std::string& groupname,
					Permission::PERMISSION_TYPE owner_mask, Permission::PERMISSION_TYPE group_mask, Permission::PERMISSION_TYPE others_mask );
		/**
		 * @brief  Constructor with initializer(s), provided for convenience.
		 * @param [in] ownername the username of the owner to be assigned
		 * @param [in] groupname the name of the group to be assigned
		 * @param [in] all_mask the rights-mask to be assigned (same for user/group/others)
		 */
		Permission( const std::string& ownername, const std::string& groupname, Permission::PERMISSION_TYPE all_mask );
		/**
		 * @brief  Constructor with initializer(s), provided for convenience.
		 * @param [in] all_mask the rights-mask to be assigned (same for user/group/others)
		 */
		Permission( Permission::PERMISSION_TYPE all_mask );
		/**
		 * @brief  Copy constructor.
		 * @param m [in] the source object to be copied
		 */
		Permission( const Permission& m );
		/**
		 * @brief  Copy constructor with (optional) overriden mask.
		 * @param [in] m the object to be copied
		 * @param [in] all_mask the rights-mask to be assigned (same for user/group/others)
		 */
		Permission( const Permission& m, Permission::PERMISSION_TYPE all_mask );
		/**
		 * @brief  Copy constructor with (optional) overriden mask.
		 * @param [in] m the object to be copied
		 * @param [in] owner_mask the rights-mask to be assigned for the owner
		 * @param [in] group_mask the rights-mask to be assigned for the group
		 * @param [in] others_mask the rights-mask to be assigned for others
		 */
		Permission( const Permission& m, Permission::PERMISSION_TYPE owner_mask, Permission::PERMISSION_TYPE group_mask, Permission::PERMISSION_TYPE others_mask );
		/**
		 * @brief  Empty destructor.
		 */
		virtual ~Permission() { }


	public:
		static std::string convertPermissionToChar( Permission::PERMISSION_TYPE mask ); // RWX
		static Permission::PERMISSION_TYPE convertCharToPermission( const std::string& data ); // RWX

/** @name Getters
 * @{
 ******************************************************************************/
	public:
		/**
		 * @brief  Get the username of the owner
		 * @return (constant) string-reference containingthe name of the user who owns the object
		 */
		const std::string& getOwner() const							{ return this->user; }
		/**
		 * @brief  Get the username of the owner
		 * @return (editable) string-reference containing the name of the user who owns the object
		 */
		std::string& getOwner()										{ return this->user; }

		/**
		 * @brief  Get the group of the object
		 * @return (constant) string-reference containing the group who owns the object
		 */
		const std::string& getGroup() const							{ return this->group; }
		/**
		 * @brief  Get the group of the object
		 * @return (editable) string-reference containing the group who owns the object
		 */
		std::string& getGroup()										{ return this->group; }

		short getMask( unsigned short mask_index ) const;

		/**
		 * @brief  Get the rights-mask as string (POSIX style)
		 * @return a STL string containing rights-mask (example: 'rwxr-wxr--')
		 */
		std::string getMask() const;

		/**
		 * @brief  Evaluate is the object was initialized (or cleared)
		 * @return true when owner, group and rights-mask are empty/zero, false else.
		 */
		bool isEmpty() const;

		std::string toUnixStyle() const;
		unsigned int toUnixStyle_size() const;

//@}
/** @name Setters
 * @{
 ******************************************************************************/
	public:
		/**
		 * @brief  Set the rights-mask
		 * @param [in] owner_mask the rights-mask to be assigned for the owner
		 * @param [in] group_mask the rights-mask to be assigned for the group
		 * @param [in] others_mask the rights-mask to be assigned for others
		 */
		void setMask( Permission::PERMISSION_TYPE owner_mask, Permission::PERMISSION_TYPE group_mask, Permission::PERMISSION_TYPE others_mask );

		/**
		 * @brief  Set the rights-mask from string
		 * @param [in] mask the rights-mask string to be assigned (example: 'rwxr-wxr--')
		 */
		void setMask( const std::string& mask );

		/**
		 * @brief  Clear all fields (owner, group, rights)
		 */
		void clear();

		/**
		 * @brief  Set the username of the owner
		 * @param [in] value the name of the user who owns the object
		 */
		void setOwner( const std::string& value )					{ this->user = value; }

		/**
		 * @brief  Set the group of the object
		 * @param [in] value the name of the group who owns the object
		 */
		void setGroup( const std::string& value )					{ this->group = value; }


		void set( const std::string& owner, const std::string& group );

		void set( const std::string& owner, const std::string& group, Permission::PERMISSION_TYPE all_mask );

		/**
		 * @brief  Set fields based on given Permissiong, (optionally) overriding mask.
		 * @param [in] m the object to be copied
		 * @param [in] all_mask the rights-mask to be assigned (same for user/group/others)
		 */
		void set( const Permission& m, Permission::PERMISSION_TYPE all_mask );

		/**
		 * @brief  Set fields based on given Permissiong, (optionally) overriding mask.
		 * @param [in] m the object to be copied
		 * @param [in] owner_mask the rights-mask to be assigned for the owner
		 * @param [in] group_mask the rights-mask to be assigned for the group
		 * @param [in] others_mask the rights-mask to be assigned for others
		 */
		void set( const Permission& m, Permission::PERMISSION_TYPE owner_mask, Permission::PERMISSION_TYPE group_mask, Permission::PERMISSION_TYPE others_mask );

		void inherit( const Permission& value, short overwrite_mode, bool only_when_empty = false );

		void setInheritedIfEmpty( const Permission* parent_perm );

		void setNobody();

		void fromString( const std::string& value );

//@}
/** @name Static helpers
 * @{
 ******************************************************************************/
	public:
		static Permission RW_RW_R__( const std::string& owner = "", const std::string& group = "" ) {
			return Permission( owner, group, Permission::RW, Permission::RW, Permission::Read );
		 }
		static Permission RW_R__R__( const std::string& owner = "", const std::string& group = "" ) {
			return Permission( owner, group, Permission::RW, Permission::Read, Permission::Read );
		 }

		static Permission R_XR__R__( const std::string& owner = "", const std::string& group = "" ) {
			return Permission( owner, group, Permission::RX, Permission::Read, Permission::Read );
		 }
		static Permission R_XR_XR__( const std::string& owner = "", const std::string& group = "" ) {
			return Permission( owner, group, Permission::RX, Permission::RX, Permission::Read );
		 }
		static Permission RWXR_____( const std::string& owner = "", const std::string& group = "" ) {
			return Permission( owner, group, Permission::RWX, Permission::Read, Permission::None );
		 }
		static Permission RWXRWX___( const std::string& owner = "", const std::string& group = "" ) {
			return Permission( owner, group, Permission::RWX, Permission::RWX, Permission::None );
		 }

//@}
/** @name Operators Overloading
 * @{
 ******************************************************************************/
	public:
		virtual Permission& operator=(const Permission& m);
		virtual bool operator==(const Permission &other) const;
		virtual bool operator!=(const Permission &other) const	{ return !(*this == other);  }
//@}
/** @name Serialization interface
 * @{
 ******************************************************************************/
	public:
		virtual std::string toString() const;
		virtual bool updateHash( DataHashContext* hash_context ) const;
//@}
/** @name Internal vars
 * @{
 ******************************************************************************/
	protected:
		std::string user;		///< owner of the object
		std::string group;		///< group of the object
		short mask[3];			///< rights in POSIX style { User/Group/Others }
		short access[3];		///< access mask in POSIX style { User/Group/Others }
//@}
	public:
		static const Permission EmptyPermission;

}; // class def

}; // namespace wosh

#endif //__WOSH_Core_Permission_H__
